package functions

import (
	"github.com/shopspring/decimal"
)

func Add_string_int(val string, num int) int64 {
	d, err := decimal.NewFromString(val)
	if err != nil {
		throwException("Addition error: %s, near ", err)
	}
	return d.Add(decimal.NewFromInt(int64(num))).IntPart()
}

func Add_int_string(num int, val string) int64 {
	d, err := decimal.NewFromString(val)
	if err != nil {
		throwException("Addition error: %s, near ", err)
	}
	return d.Add(decimal.NewFromInt(int64(num))).IntPart()
}

func Add_decimal_int(val decimal.Decimal, num int) int64 {
	return val.Add(decimal.NewFromInt(int64(num))).IntPart()
}

func Add_int_decimal(num int, val decimal.Decimal) int64 {
	return val.Add(decimal.NewFromInt(int64(num))).IntPart()
}

func Add_any_float(val interface{}, num float64) float64 {
	var d decimal.Decimal
	switch v := val.(type) {
	case int:
		d = decimal.NewFromInt(int64(v)).Add(decimal.NewFromFloat(num))
	case int64:
		d = decimal.NewFromInt(v).Add(decimal.NewFromFloat(num))
	case int32:
		d = decimal.NewFromInt32(v).Add(decimal.NewFromFloat(num))
	case float64:
		d = decimal.NewFromFloat(v).Add(decimal.NewFromFloat(num))
	case float32:
		d = decimal.NewFromFloat32(v).Add(decimal.NewFromFloat(num))
	case string:
		fd, err := decimal.NewFromString(v)
		if err != nil {
			throwException("Addition error: %s, near ", err)
		}
		d = fd.Add(decimal.NewFromFloat(num))
	case decimal.Decimal:
		d = v.Add(decimal.NewFromFloat(num))
	default:
		throwException("Addition error: mismatched types %T and %T, near ", val, num)
	}
	f, _ := d.Float64()
	return f
}

func Add_float_any(num float64, val interface{}) float64 {
	var d decimal.Decimal
	switch v := val.(type) {
	case int:
		d = decimal.NewFromInt(int64(v)).Add(decimal.NewFromFloat(num))
	case int64:
		d = decimal.NewFromInt(v).Add(decimal.NewFromFloat(num))
	case int32:
		d = decimal.NewFromInt32(v).Add(decimal.NewFromFloat(num))
	case float64:
		d = decimal.NewFromFloat(v).Add(decimal.NewFromFloat(num))
	case float32:
		d = decimal.NewFromFloat32(v).Add(decimal.NewFromFloat(num))
	case string:
		fd, err := decimal.NewFromString(v)
		if err != nil {
			throwException("Addition error: %s, near ", err)
		}
		d = fd.Add(decimal.NewFromFloat(num))
	case decimal.Decimal:
		d = v.Add(decimal.NewFromFloat(num))
	default:
		throwException("Addition error: mismatched types %T and %T, near ", num, val)
	}
	f, _ := d.Float64()
	return f
}

func Add_decimal_decimal(v1, v2 decimal.Decimal) interface{} {
	d := v1.Add(v2)
	f, ok := d.Float64()
	if ok {
		return d.IntPart()
	}
	return f
}
